import cv2
import numpy as np
import matplotlib.pyplot as plt
from math import sqrt
from xml.dom.minidom import parse
import pytesseract
import os

print("温馨提示：本机为", os.cpu_count(), "核CPU")
pytesseract.pytesseract.tesseract_cmd = r'C:\\Program Files\\Tesseract-OCR\\tesseract.exe'
tessdata_dir_config = '--tessdata-dir "c:\\Program Files\\Tesseract-OCR\\tessdata" --psm 7'


# 对“标准” 和“实测”单元格进行识别，生成对应的数据
def distinguish(shice_list, biaozhun_list, Cell_FilePath):
    """
    该函数的作用：根据实测值、标准值的索引读取其对应的单元格图像并进行识别
    :param shice_list: 待识别的单元格信息
    :param biaozhun_list: 待识别的标准单元格信息
    :param Cell_FilePath: 单元格图象的存放地址
    :return:
    """
    # 存放实测值单元格图象的识别结果
    shice = []
    # 存放标准值单元格图象的识别结果
    biaozhun = []

    img_read = cv2.imread
    image_to_string = pytesseract.image_to_string

    for i in range(len(biaozhun_list)):
        # 读取标准值单元格图像的索引
        biaozhun_index = [x[-1] for x in biaozhun_list[i]]
        biaozhun_l = []
        for index in biaozhun_index:
            img = img_read(Cell_FilePath + str(index) + '.jpg')

            text = image_to_string(img, lang="1214", config=tessdata_dir_config)
            text = text.replace(' ', '')
            biaozhun_l.append(text[0:-2])
        biaozhun.append(biaozhun_l)

        l_shice = []
        # 一个标准值可能对应多组实测值
        for index_list in shice_list[i]:

            # index_list 的结构[[10, 5], 55, 0]
            # 该实测值对应的实测单元格图像的索引
            shice_list_samebiaozhun = [x[1] for x in index_list]
            # 该实测值对应的标准单元格索引
            shice_biaozhun_index = [x[-1] for x in index_list]
            # 实测值对应的行列信息
            index_cell_points = [x[0] for x in index_list]
            shice_l = []
            for m, shice_index in enumerate(shice_list_samebiaozhun):
                img = img_read(Cell_FilePath + str(shice_index) + '.jpg')
                text = image_to_string(img, lang='font2', config=tessdata_dir_config)
                text = text.replace(' ', '')
                print(text[0:-2])
                shice_l.append([text[0:-2], shice_biaozhun_index[m], index_cell_points[m]])
            l_shice.append(shice_l)

        shice.append(l_shice)

    return shice, biaozhun


def draw_mask(img, box, color):
    """
    该函数的作用：绘制掩码
    :param img: 待绘制图像
    :param box: 掩码位置信息
    :param color: 掩码颜色
    :return: 返回完成绘制的图像
    """
    # box = [xl, yl, xr, yr]
    zeros = np.zeros((img.shape), dtype=np.uint8)
    if (color == 1):  # 颜色为绿色，即合格

        zeros_mask = cv2.rectangle(zeros, (box[0], box[1]), (box[2], box[3]),
                                   color=(0, 255, 0), thickness=-1)  # thickness=-1 表示矩形框内颜色填充
    else:
        zeros_mask = cv2.rectangle(zeros, (box[0], box[1]), (box[2], box[3]),
                                   color=(0, 0, 255), thickness=-1)  # thickness=-1 表示矩形框内颜色填充
    # 透明度
    alpha = 0.8
    beta = 0.8

    mask_img = cv2.addWeighted(img, alpha, zeros_mask, beta, 0)

    return mask_img


# 根据标准中的字符串确定标准范围
# 根据标准范围对实测进行评估
# 输出结果反应在图像中，合格为绿色，不合格标红
def assess(biaozhun_list, shice_list, real_cell_points, img_jiaozheng):
    """
    该函数的作用：根据表格图像中标准范围对实测进行评估，输出结果反应在图像中，合格为绿色，不合格标红
    :param biaozhun_list: 识别得到的标准值
    :param shice_list: 识别得到的实测值
    :param real_cell_points: 单元格对应在图像中真实的位置坐标信息
    :param img_jiaozheng: 校正后的图像
    :return: 返回将评估结果以掩码绘制在矫正后的表格图像
    """
    for standard_index, value_measured_class in enumerate(shice_list):

        standard_list = biaozhun_list[standard_index]

        for value_measured_list in value_measured_class:
            # 掩码颜色标志点
            color = 0
            for value_measured in value_measured_list:

                # 如果单元格识别内容中有‘\’， 说明该单元格的内容无需进行评估
                if '/' in list(value_measured[0]):
                    break

                # 实测值对应的标准值的索引
                value_StandardIndex = value_measured[1]
                # 每个单元格的图像中的真实位置
                real_points = real_cell_points[value_measured[-1][0]][value_measured[-1][1]]
                # 从矫正后的图像剪取该待测单元格图像
                cell_img = img_jiaozheng[real_points[0]:real_points[1], real_points[2]:real_points[3]]
                #                 x_center = int ((real_points[0] + real_points[1]) / 2)
                #                 y_center = int((real_points[2] + real_points[3]) 2 )

                # 计算掩码框的大小 掩码绘制为单元格图像的4/5左右
                h_cell = int(real_points[1] - real_points[0])
                w_cell = int(real_points[3] - real_points[2])
                box_xl = int(w_cell / 5)
                box_yl = int(h_cell / 5)
                box_xr = int(w_cell / 5 * 4)
                box_yr = int(h_cell / 5 * 4)
                box = [box_xl, box_yl, box_xr, box_yr]

                print('real_points:', real_points)

                # 将识别得到的待评估的内容转化为数字类型，便之后的比较
                value_measured = float(value_measured[0])
                # 通过实测值对应的标准值的索引取得该待检测内容的检测范围
                value_standard = standard_list[value_StandardIndex]

                print("value_measured:", value_measured)
                print("value_standard:", value_standard)
                if "≥" in value_standard:
                    value_standard = value_standard.replace('≥', '')
                    value_standard = float(value_standard)

                    if value_measured >= value_standard:
                        print("合格！")
                        color = 1

                    else:
                        print("不合格！")
                elif "≤" in value_standard:

                    value_standard = value_standard.replace('≤', '')
                    value_standard = float(value_standard)

                    if value_measured <= value_standard:
                        print("合格！")
                        color = 1
                    else:
                        print("不合格！")

                elif "-" in value_standard:

                    value_standard = list(value_standard)
                    print(value_standard)
                    i = value_standard.index("-")
                    value_standard_start = float(''.join(value_standard[:i]))
                    value_standard_end = float(''.join(value_standard[i + 1:]))
                    if value_standard_start <= value_measured <= value_standard_end:
                        print("合格！")
                        color = 1
                    else:
                        print("不合格！")
                print("box:", box)
                print(cell_img.shape)
                mask_img = draw_mask(cell_img, box, color)
                img_jiaozheng[real_points[0]:real_points[1], real_points[2]:real_points[3]] = mask_img
                # plt.imshow(mask_img)

    return img_jiaozheng


def execel_information(Rows, All_cell_points):
    """
    该函数的作用：读取表格中的主要信息以及其对应的内容的单元格图像的索引，如‘报告编号’，以及其对应内容的单元格图像索引
    :param Rows: 表格的行信息
    :param All_cell_points: 表格解析得到的每个单元格的信息
    :return: record_information 其中的元素类似 ['报告编号'， ‘报告编号’对应的坐标值和单元格图像的索引， ‘报告编号’对应的内容的坐标值和单元格图像的索引]
    """
    record_information = []

    for index_row in range(len(Rows)):

        # 获取每一行中的单元格并计算
        cells = Rows[index_row].getElementsByTagName('Cell')
        num_cells = len(cells)
        information = []
        for index_cell, cell in enumerate(cells):

            data = cell.getElementsByTagName('Data')

            if len(data):

                value = data[0].childNodes[0].data

                if ("报告编号" in value or '结论' in value or '审核' in value
                        or '校对' in value or "验收标准" in value or "试验员" in value):
                    # print('yes')
                    print(value)
                    # 返回“报告编号”， 及其图像中真实的坐标值， 以及其所对应内容的图像中真实的坐标值
                    information.append([value, [All_cell_points[index_row][index_cell], [index_row, index_cell]],
                                        [All_cell_points[index_row][index_cell + 1], [index_row, index_cell + 1]]])
                    record_information.append([value, [All_cell_points[index_row][index_cell], [index_row, index_cell]],
                                               [All_cell_points[index_row][index_cell + 1],
                                                [index_row, index_cell + 1]]])

    return record_information


def get_information(excel_information, cells_binary_path):
    """
    该函数的作用：根据索引读取单元格图片并识别表格主要的信息对应的内容
    :param excel_information: 表格主要的信息以及其对应的内容的索引
    :param cells_binary_path: 单元格图像存放的位置
    :return: information :类似 [['报告编号:ReportNo.', '202010247-8']]
    """
    img_read = cv2.imread
    image_to_string = pytesseract.image_to_string
    information = []
    for index_information in excel_information:
        index_img = index_information[-1][0][-1]
        print(index_img)
        value = index_information[0]
        img = img_read(cells_binary_path + str(index_img) + '.jpg')
        text = image_to_string(img, lang="font2", config=tessdata_dir_config)
        text = text.replace(' ', '')
        value = value.replace(' ', '')
        text = text[0:-2].replace('\n', '')
        # text = value + ' : '+str(text)
        information.append([value, text])
    return information


def mask_information(real_cell_points, excel_information, excel_distinguished_information, img_jiaozheng):
    """
    该函数的作用：
    :param real_cell_points:
    :param excel_information:
    :param excel_distinguished_information:
    :param img_jiaozheng:
    :return:
    """
    color = 0
    for index, excel in enumerate(excel_information):
        print(excel)
        if '报告编号' in excel[0] and excel_distinguished_information[index][1] != '':
            color = 1
        if '试验员' in excel[0] and excel_distinguished_information[index][1] != '':
            color = 1
        if '验收标准' in excel[0] and excel_distinguished_information[index][1] != '':
            color = 1
        if '结论' in excel[0] and excel_distinguished_information[index][1] == '合格':
            color = 1
        if '校对' in excel[0] and excel_distinguished_information[index][1] == '':
            color = 1
        if '审核' in excel[0] and excel_distinguished_information[index][1] == '':
            color = 1
        for cell in excel[1:]:
            real_points = real_cell_points[cell[-1][0]][cell[-1][1]]
            cell_img = img_jiaozheng[real_points[0]:real_points[1], real_points[2]:real_points[3]]
            print(cell_img.shape)
            h_cell = int(real_points[1] - real_points[0])
            w_cell = int(real_points[3] - real_points[2])
            box_xl = int(w_cell / 5)
            box_yl = int(h_cell / 5)
            box_xr = int(w_cell / 5 * 4)
            box_yr = int(h_cell / 5 * 4)
            box = [box_xl, box_yl, box_xr, box_yr]
            mask_img = draw_mask(cell_img, box, color)
            img_jiaozheng[real_points[0]:real_points[1], real_points[2]:real_points[3]] = mask_img